/**
 * @file ggs.h
 *
 * A ggs client in C language adapted from kitty's
 * GGS_client.C (in C++) by Igord Durdanovic.
 *
 * TODO: all this code should be rewritten!
 *
 * @date 2002 - 2011
 * @author Richard Delorme
 * @version 4.1
 */

#ifndef EDAX_GGS_H
#define EDAX_GGS_H

#include "socket.h"
#include "util.h"
#include <stdio.h>

#define TEXT_SIZE 4096
#define LINE_SIZE 1024
#define GGS_BOARD_SIZE 200 /* 14 * 14 ok ! */
#define MOVELIST_SIZE 200

enum {
	GGS_UNDEF = 0,
	GGS_REQUEST_ON,
	GGS_MATCH_ON,
	GGS_MATCH_OFF,
	GGS_BOARD,
	GGS_OS_ON,
	GGS_OS_OFF,
	GGS_WATCH_ON,
	GGS_WATCH_OFF,
	GGS_WATCH_BOARD,
	GGS_ADMIN_CMD,
	GGS_SAIO_DELAY,
	GGS_QUIT
};

enum {
	GGS_PARSE_OK = 0,
	GGS_PARSE_BAD_INT,
	GGS_PARSE_BAD_INT_RANGE,
	GGS_PARSE_BAD_DOUBLE,
	GGS_PARSE_BAD_DOUBLE_RANGE,
	GGS_PARSE_BAD_MOVE,
	GGS_PARSE_BAD_TIME,
	GGS_PARSE_BAD_CLOCK,
	GGS_PARSE_BAD_PLAYER,
	GGS_PARSE_BAD_REQUEST,
	GGS_PARSE_BAD_MATCH_ON,
	GGS_PARSE_BAD_MATCH_OFF,
	GGS_PARSE_BAD_OS_ON,
	GGS_PARSE_BAD_OS_OFF,
	GGS_PARSE_BAD_BOARD,
	GGS_PARSE_BAD_ADMIN,
	GGS_PARSE_BAD_SAIO_DELAY
};

typedef struct GGSText {
	char line[TEXT_SIZE][LINE_SIZE];
	int n_lines;
} GGSText;

typedef struct GGSClock {
	int ini_flag; /* true = NOT loss */
	int inc_flag; /* true = NOT additive */
	int ext_flag; /* true = NOT add */

	int ini_move;
	int inc_move;
	int ext_move;

	double ini_time;
	double inc_time;
	double ext_time;
} GGSClock;

typedef struct GGSPlayer {
	char *name;
	double rating;
} GGSPlayer;

typedef struct GGSMatchType {
	int is_saved;
	int is_rated;
	int is_synchro;
	int is_komi;
	int is_rand;
	int is_anti;
	int discs;
	int size;
} GGSMatchType;

typedef struct GGSMatch {
	char *id;
	GGSPlayer player[2];
} GGSMatch;

typedef struct GGSMatchOff {
	char *id;
	GGSPlayer player[2];
} GGSMatchOff;

typedef struct GGSMatchOn {
	char *id;
	GGSPlayer player[2];
	GGSMatchType match_type[1];
} GGSMatchOn;

typedef struct GGSRequest {
	char *id;
	GGSPlayer player[2];
	GGSMatchType match_type[1];
	GGSClock clock[2];
} GGSRequest;

typedef struct GGSBoard {
	char *id;
	GGSPlayer player[2];
	GGSMatchType match_type[1];
	GGSClock clock[2];
	double komi;
	int is_join;
	int is_update;
	int move;
	int move_no;
	char color[2];
	char board[GGS_BOARD_SIZE];
	char turn;
	char board_init[GGS_BOARD_SIZE];
	char turn_init;
	int move_list[MOVELIST_SIZE];
	int move_list_n;
} GGSBoard;


typedef struct GGSAdmin {
	char *command;
	char name[16];
} GGSAdmin;

/* the GGSClient structure */
typedef struct GGSClient {
	GGSBoard board[1];
	GGSRequest request[1];
	GGSMatchOn match_on[1];
	GGSMatchOff match_off[1];
	GGSAdmin admin[1];
	GGSText message;
	char *send_buffer;
	char *recv_buffer;
	int sock;
	int type;
	const char *me;
	// extension
	bool is_playing;
	long long last_refresh;
	struct {
		char *cmd;
		int i;
		long long delay;
	} loop[1];
	struct {
		char *cmd;
		long long delay;
	} once[1];		
} GGSClient;

void ggs_string_copy(char **dest, const char *src);
void ggs_text_init(GGSText *text);
int ggs_text_add(GGSText *text, const char *buffer);
void ggs_text_print(GGSText *text, FILE *f);

const char *ggs_parse(const char *line, char *word);
const char *ggs_parse_until(const char *line, char *word, const char mark);
const char *ggs_skip_word(const char *line);
const char *ggs_skip_until(const char *line, const char mark);
int ggs_int_parse(int *value, const char *word);
int ggs_double_parse(double *value, const char *word);
int ggs_move_parse(int *move, const char *word);
int ggs_time_parse(double *time, const char *word);
void ggs_time_print(double t, FILE *f);
int ggs_clock_parse(GGSClock *ggsclock, const char *word);
void ggs_clock_print(GGSClock *ggsclock, FILE *f);
int ggs_player_name_parse(GGSPlayer *player, const char *name);
int ggs_player_parse(GGSPlayer *player, const char *name, const char *rating);
void ggs_player_print(GGSPlayer *player, FILE *f);
int ggs_match_type_parse(GGSMatchType *match, const char *word);
void ggs_match_type_print(GGSMatchType *match, FILE *f);
int ggs_request_parse(GGSRequest *request, GGSText *text);
void ggs_request_print(GGSRequest *request, FILE *f);
int ggs_match_on_parse(GGSMatchOn *on, GGSText *text);
void ggs_match_on_print(GGSMatchOn *on, FILE *f);
int ggs_match_off_parse(GGSMatchOff *off, GGSText *text);
void ggs_match_off_print(GGSMatchOff *off, FILE *f);
int ggs_board_parse(GGSBoard *board, GGSText *text);
void ggs_board_print(GGSBoard *board, FILE *f);
int ggs_admin_parse(GGSAdmin *admin, GGSText *text);
int ggs_os_off_parse(GGSText *text);
int ggs_os_on_parse(GGSText *text);

GGSClient *ggs_client_create(void);
void ggs_client_destroy(GGSClient *client);
void ggs_client_connect(GGSClient *client, const char *host, int port);
void ggs_client_disconnect(GGSClient *client);
void ggs_client_process(GGSClient *client);
void ggs_client_open_input(GGSClient *client);
void ggs_client_close_input(GGSClient *client);
void ggs_client_send(GGSClient *client, const char*, ...);
void ggs_client_clean(GGSClient *client);
int ggs_client_ready(GGSClient *client);

#endif /* EDAX_GGS_H */
